﻿using System.Collections.Generic;
using System.Xml;

namespace Jayden.Dll.Sc2.Descriptions
{
	public class BuildActionDescription : ActionDescription
	{
		private string m_BuildId;
		private EntityDescription m_Build;
		
		protected BuildActionDescription(EntityDescription entity, EntityDescription build, string id, string name = null, string iconId = null)
			: base(entity, id, name, iconId)
		{
			m_BuildId = build.Id;
			m_Build = build;
		}
		public BuildActionDescription(EntityDescription entity, XmlNode node, string format = "{0}Build{1}", string nameFormat = "{0} build {1}")
			: base(entity, string.Format(format, entity.Id, node.Attributes["id"].Value), nameFormat)
		{
			XmlAttribute icon = node.Attributes["icon"];
			if (icon != null)
				m_IconId = icon.Value;
			m_BuildId = node.Attributes["id"].Value;
		}

		protected string NameFormat { get { return base.Name; } }
		public override string Name { get { return string.Format(NameFormat, Entity.Name, Build.Name); } }

		public EntityDescription Build
		{
			get
			{
				if (m_Build == null && m_BuildId != null)
					m_Build = Entity.Race[m_BuildId];
				return m_Build;
			}
		}

		public override bool IsAccessible(GameState state)
		{
			foreach (EntityDescription required in Build.Requirements)
				if (state[required] == null)
					return false;
			if (Build.Mineral > 0 && state.Mineral < Build.Mineral && state.WorkerOnMineral <= 0)
				return false;
			if (Build.Vespene > 0 && state.Vespene < Build.Vespene && state.WorkerOnGas <= 0)
				return false;
			if (Build.Supply < 0 && state.Food + state.FoodBuilding + Build.Supply < 0)
				return false;
			if(Build.IsVespene)
			{
				GameState.EntityState entityState = state[Build];
				if (entityState != null)
				{
					int maxCount = (state.Bases + state.BasesBuilding) * Rules.ExtractorPerBase;
					if (entityState.Total >= maxCount)
						return false;
				}
			}
			return base.IsAccessible(state);
		}

		public override bool IsExecutable(GameState state)
		{
			foreach (EntityDescription required in Build.Requirements)
				if (!state.HaveRequirement(required))
					return false;
			GameState.EntityState entityState = state[Entity];
			if (entityState == null || entityState.Idle <= 0)
				return false;
			if (Build.Supply < 0 && state.Food + Build.Supply < 0)
				return false;
			if (Build.Mineral > 0 && state.Mineral < Build.Mineral)
				return false;
			if (Build.Vespene > 0 && state.Vespene < Build.Vespene)
				return false;
			foreach (KeyValuePair<EntityDescription, int> pair in Build.InputDictionary)
			{
				entityState = state[pair.Key];
				if (entityState == null || entityState.Idle < pair.Value)
					return false;
			}
			return base.IsExecutable(state);
		}

		protected void RemoveResources(GameState state)
		{
			state.Mineral -= Build.Mineral;
			state.Vespene -= Build.Vespene;
		}

		public override void Execute(GameState state)
		{
			if (Entity.IsWorker)
			{
				if (state.WorkerOnMineral > 0)
					state.WorkerOnMineral--;
				else
					state.WorkerOnGas--;
				if (state.Race.Id == "Protoss")
				{
					state.Add(new DelayedActionDescription(this, 2 + state.Time, delegate(GameState innerState)
					{
						innerState.Add(Entity, 0, 1, 0);
						state.WorkerOnMineral++;
					}, "ProbeReturnToMineral"));
				}
			}

			RemoveResources(state);
			state.Add(Entity, 0, -1, 0);
			state.Add(Build, 1, 0, 1);
			foreach (KeyValuePair<EntityDescription, int> pair in Build.InputDictionary)
				state.Add(pair.Key, 0, -pair.Value, -pair.Value);
			BaseExecute(state);
			DelayedActionDescription delayed = new DelayedActionDescription(this, Build.Time + state.Time, delegate(GameState innerState)
			{
				if (!Entity.IsWorker)
					innerState.Add(Entity, 0, 1, 0);
				innerState.Add(Build, -1, 1, 0);

				if (Entity.IsWorker && Entity.Race.Id == "Terran")
				{
					innerState.Add(Entity, 0, 1, 0);
					if (Build.IsVespene)
						state.WorkerOnGas++;
					else
						state.WorkerOnMineral++;
				}
			});
			if (Build.Time > 0)
				state.Add(delayed);
			else
				delayed.Execute(state);
		}

		public override string IconId { get { return m_IconId ?? Build.IconId; } }

		protected void BaseExecute(GameState state)
		{
			base.Execute(state);
		}
	}
}
